package fun_Implement

import (
	"gitee.com/huanminabc/go-utils/cmd"
	"gitee.com/huanminabc/go-utils/code_analysis"
	"gitee.com/huanminabc/go-utils/common"
	"gitee.com/huanminabc/go-utils/vars"
	"go-CodeAnalysis/expression"
	"go-LineScriptCommand/container"
	"go-LineScriptCommand/global"
	"go-LineScriptCommand/manager"
	"golang.org/x/text/cases"
	"golang.org/x/text/language"
	"regexp"
	"strconv"
	"strings"
)

func init() {
	var funs = []container.Fun{}
	//注册函数
	common.InsertSliceBatch(&funs,
		grep,
		scan,
		pick,
		replace,
		del,
		delRange,
		delLine,
		split,
		join,
		_len_,
		count,
		lines,
		sub,
		index,
		lastIndex,
		at,
		concat,
		trim,
		upper,
		lower,
		camel,
		reverse,
		contain,
		startWith,
		endWith,
		charAt,
		format,
		and,
		or,
		not,
		eq,
		eqIgnore,
		gt,
		ge,
		lt,
		le,
		ne,
		_if_,
		_system_,
		sync,
		reset,
	)
	container.RegisterFunList(funs)
	container.RegisterType("base", funs)

}

// 字符串替换
func replace(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 字符串替换 
签名: replace(字符串,查找字符串,替换字符串,all)
- all: 是否全部替换,默认是只替换第一个,如果是all那么就替换全部
查找字符串:支持正则表达式 '/xxx/'  例如: /45|wo/
案例:
1. replace('hello world','world','golang')  结果:  hello golang
2. replace('hello 123 wo123rld','/\\d+/','golang','all')  结果:  hello golang world
`
	}

	if len(args) == 2 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) == 3 { //如果没有all那么就加一个空字符串
		args = append(args, "")
	}

	if len(args) != 4 {
		panic("replace函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	old := args[1]
	tag := args[3]
	//判断是否是匹配一个还是全部
	var isAll bool
	if tag == "all" {
		isAll = true
	}

	//判断是否是正则表达式
	var isReg bool
	if strings.HasPrefix(old, "/") && strings.HasSuffix(old, "/") {
		old = old[1 : len(old)-1]
		isReg = true
	}
	newStr := args[2]
	if isReg {
		//正则替换
		if isAll {
			str = common.RegexpReplace(str, old, newStr)
		} else {
			str = common.RegexpReplaceFirst(str, old, newStr)
		}
	} else {
		//替换
		if isAll {
			str = strings.Replace(str, old, newStr, -1)
		} else {
			str = strings.Replace(str, old, newStr, 1)
		}

	}
	return global.AddStrSymbol(str)
}

func del(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 删除字符串
签名: del(字符串,删除字符串)
- 删除字符串,支持正则表达式 '/xxx/'  例如: /45|wo/
案例:
1. del('hello world','world')  结果:  hello
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("del函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	sub_ := args[1]
	//判断是否是正则表达式
	var isReg bool
	if strings.HasPrefix(sub_, "/") && strings.HasSuffix(sub_, "/") {
		sub_ = sub_[1 : len(sub_)-1]
		isReg = true
	}

	//删除
	if isReg {
		re := regexp.MustCompile(sub_)
		str = re.ReplaceAllString(str, "")
	} else {
		str = strings.Replace(str, sub_, "", -1)
	}
	return str
}
func delRange(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 删除字符串的范围
签名: delRange(字符串,开始位置,结束位置)
- 开始位置从0开始
- 结束位置从1开始 这个可以不写,默认为字符串的总长度
案例:
1. delRange('hello world',1,5)  结果:  h world
2. delRange('hello world',6)  结果:  hello
注意:
1.在管道传输场景下前一个管道的值会作为第一个参数  xxx|delRange(1,5)  这里的xxx会作为delRange第一个参数,这个过程是强制的。
2.如果不想使用前一个管道的值,那么可以使用delRange('hello world',1,5)这种方式, 也就是三个参数全部写全。
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if (len(args) == 2 || len(args) == 1) && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) == 2 {
		//那么第三个参数就是第1个参数的总长度
		args = append(args, strconv.Itoa(len(args[0])))
	}
	if len(args) != 3 {
		panic("delRange函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	strlen := len(str)
	start, _ := strconv.Atoi(args[1])
	//效验开始位置不能小于0也不能大于字符串长度
	if start < 0 || start > strlen {
		panic("开始位置不能小于0也不能大于字符串长度")
	}
	end, _ := strconv.Atoi(args[2])
	if end < 1 || end > strlen {
		panic("结束位置不能小于1也不能大于字符串长度")
	}

	//删除
	str = str[:start] + str[end:]
	return str

}

// 删除行
func delLine(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 删除行
签名: delLine(多行字符串,行号)
- 行号从1开始
案例:
1. delLine('hello\nworld\nabc',2)  结果:  hello\nabc
`
	}
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("delLine函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	line, _ := strconv.Atoi(args[1])
	//获取行数
	strSplit := strings.Split(str, global.LineBreak)
	//效验行数
	if line < 1 || line > len(strSplit) {
		panic("行号不能小于1也不能大于总行数")
	}
	//删除
	strSplit = append(strSplit[:line-1], strSplit[line:]...)
	return strings.Join(strSplit, global.LineBreak)
}

// 字符串分割
func split(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 字符串分割
签名: split(字符串,分割符)
案例:
1. split('hello world',' ')  结果:  hello\nworld
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}

	//判断参数个数
	if len(args) != 2 {
		panic("split函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	sep := args[1]
	//分割
	strSplit := strings.Split(str, sep)
	join_ := strings.Join(strSplit, global.LineBreak)
	return join_
}

// 将多行字符串合并成一行
func join(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 将多行字符串合并成一行
签名: join(多行字符串)
案例:
1. join('hello\nworld')  结果:  helloworld
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 1 {
		panic("join函数参数个数不正确")

	}
	//拆分参数
	str := args[0]
	//去掉换行符
	str = strings.ReplaceAll(str, global.LineBreak, "")
	return str
}

// 获取字符串的长度
func _len_(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 获取字符串长度
签名: len(字符串)
案例:
1. len('hello world')  结果:  11
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 1 {
		panic("len函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	//字符串",不参与计算长度
	str = global.RemoveStrSymbol(str)
	//获取有几个自定义换行符
	count_ := strings.Count(str, global.LineBreak)
	//排除自定义换行符的长度
	strLen := len(str) - count_*len(global.LineBreak) + count_
	return strconv.Itoa(strLen)
}
func count(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 获取字符串出现的次数
签名: count(字符串,查找字符串)
- 返回查找字符串出现的次数
案例:
1. count('hello world','o')  结果:  2
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("count函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	sub_ := args[1]
	//获取次数
	count_ := strings.Count(str, sub_)
	return strconv.Itoa(count_)
}

// 获取行数
func lines(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 获取行数
签名: lines(多行字符串)
案例:
1. lines('hello\nworld')  结果:  2
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 1 {
		panic("lines函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	//获取行数
	strSplit := strings.Split(str, global.LineBreak)
	return strconv.Itoa(len(strSplit))
}

// 字符串截取
func sub(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 字符串截取
签名: sub(字符串,开始位置,截取长度) 开
- 始位置从0开始 
- 截取长度从1开始  这个可以不写,默认为字符串的总长度
案例:
1. sub('hello world',1,5)  结果:  hello
2. sub('hello world',6)  结果:  world
注意:
1.在管道传输场景下前一个管道的值会作为第一个参数  xxx|sub(1,5)  这里的xxx会作为sub第一个参数,这个过程是强制的。
2.如果不想使用前一个管道的值,那么可以使用sub('hello world',1,5)这种方式, 也就是三个参数全部写全。
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if (len(args) == 2 || len(args) == 1) && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) == 2 {
		//那么第三个参数就是第1个参数的总长度
		args = append(args, strconv.Itoa(len(args[0])))
	}

	//判断参数个数
	if len(args) != 3 {
		panic("sub函数参数个数不正确")
	}
	//拆分参数
	str := args[0]

	strlen := len(str)
	start, _ := strconv.Atoi(args[1])
	//效验开始位置不能小于0也不能大于字符串长度
	if start < 0 || start > strlen {
		panic("开始位置不能小于0也不能大于字符串长度")
	}
	length, _ := strconv.Atoi(args[2])
	//length不能小于1
	if length < 1 || length > strlen {
		panic("截取长度不能小于1也不能大于字符串长度")
	}
	//截取
	strSub := str[start:length]
	//判断是否是数值或者布尔值,如果是那么就不加双引号
	if common.IsNumber(str) || common.IsBool(str) {
		return strSub
	}
	//去掉开头和结尾的"
	strSub = global.RemoveStrSymbolStartOrEnd(strSub)
	return global.AddStrSymbol(strSub)
}

// 获取指定字符串的位置
func index(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 获取指定字符串的位置
签名: index(字符串,查找字符串)
- 返回查找字符串的位置,如果没有找到则返回-1
- 位置从0开始
案例:
1. index('hello world','world')  结果:  6
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 2 {
		panic("index函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	sub_ := args[1]
	//获取位置
	index_ := strings.Index(str, sub_)
	return strconv.Itoa(index_)
}

// 获取最后一个字符串的位置
func lastIndex(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 获取最后一个字符串的位置
签名: lastIndex(字符串,查找字符串)
- 返回查找字符串的位置,如果没有找到则返回-1
- 位置从0开始
案例:
1. lastIndex('hello world','o')  结果: 7
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 2 {
		panic("last_index函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	sub_ := args[1]
	//获取位置
	index_ := strings.LastIndex(str, sub_)
	return strconv.Itoa(index_)
}

//func show(args ...string) string {
//	//判断第一个参数是-doc
//	if len(args) > 0 && args[0] == "-doc" {
//		return `
//功能: 显示文件内容
//签名: show(文件路径,options)
//- 文件路径: 文件路径
//- options(字符串): 选项(组合可以联合使用(逗号分割),独立不能和组合一起使用)
//- - n: 显示行号 (组合)
//- - hx: 显示前x行 (组合) ,也可以是h2,h3
//- - tx: 显示后x行 (组合) ,也可以是t2,t3
//- - f: 持续显示,直到ctrl+c结束 (独立)
//案例:
//
//}

// 搜索字符串在管道中的第几行
func grep(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 搜索字符串在管道中的第几行
签名: grep(lines,字符串,options)
- lines: 多行字符串 \n结尾就是一行
- 字符串: 要搜索的字符串 ,如果前后使用/xxx/ 则表示正则表达式进行匹配
- options(字符串): 选项(组合可以联合使用(逗号分割),独立不能和组合一起使用)
- - n: 显示行号 (组合)
- - a1: 显示前1行 (组合) ,也可以是a2,a3
- - b1: 显示后1行 (组合) ,也可以是b2,b3
- - c1: 显示前后1行 (组合) ,也可以是c2,c3
- - i:  忽略大小写 (组合)
- - ln: 输出第一次匹配行的行号 (独立)
- - lni: 输出第一次匹配行的行号(忽略大小写) (独立)

案例:
1. grep('hello wo45rld\nxxx45xw\norld','orld','n,a1') 结果:  nxxx45xw\norld
2. grep('hello wo45rld\nxxx45xw\norld','orld','ln') 结果:  3
3. grep('hello wo45rld\nxxx45xw\norld','/45|wo/','n') 结果:  1:hello wo45rld\n2:xxx45xw
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
		//如果没有options那么就加一个空字符串
		args = append(args, "")
	}
	if len(args) == 2 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) == 2 && container.GetPrePipelineData().Data == "" {
		//如果没有options那么就加一个空字符串
		args = append(args, "")
	}
	//判断参数个数
	if len(args) != 3 {
		panic("grep函数参数个数不正确")
	}
	//拆分参数
	str := args[0]     //多行字符串
	sub_str := args[1] //要搜索的字符串
	options := args[2] //选项
	//判断是否是正则表达式
	var isReg bool
	if strings.HasPrefix(sub_str, "/") && strings.HasSuffix(sub_str, "/") {
		sub_str = sub_str[1 : len(sub_str)-1]
		isReg = true
	}

	//分割选项
	optionsSplit := strings.Split(options, ",")
	//判断0是否是空
	if optionsSplit[0] == "" {
		optionsSplit = []string{}
	}

	//开关大小写
	var isCase bool
	if common.SliceContains(&optionsSplit, "i") {
		isCase = true
	}

	//获取行数
	strSplit := strings.Split(str, global.LineBreak)

	//判断是否返回行号
	if lni := common.SliceContains(&optionsSplit, "lni"); common.SliceContains(&optionsSplit, "ln") || lni {
		for i, v := range strSplit {
			if lni { //忽略大小写
				if isReg {
					re := regexp.MustCompile("(?i)" + sub_str) //忽略大小写进行匹配

					if re.MatchString(strings.ToLower(v)) {
						return strconv.Itoa(i + 1)
					}
					continue
				}

				if strings.Contains(strings.ToLower(v), strings.ToLower(sub_str)) {
					return strconv.Itoa(i + 1)
				}
			} else {
				if isReg {
					re := regexp.MustCompile(sub_str)
					if re.MatchString(v) {
						return strconv.Itoa(i + 1)
					}
					continue
				}

				if strings.Contains(v, sub_str) {
					return strconv.Itoa(i + 1)
				}
			}
		}
	}
	//判断是否加行号
	var lineNum bool
	if common.SliceContains(&optionsSplit, "n") {
		lineNum = true
	}

	var indexs []int
	for i, v := range strSplit {
		if isCase { //忽略大小写
			if isReg {
				re := regexp.MustCompile("(?i)" + sub_str) //忽略大小写进行匹配

				if re.MatchString(strings.ToLower(v)) {
					//给匹配的行中的关键字加上颜色, 下面ReplaceAllStringFunc是将匹配到的字符串加上颜色
					strSplit[i] = re.ReplaceAllStringFunc(v, func(s string) string {
						return vars.RedColor(s)
					})
					indexs = append(indexs, i) //记录匹配到的行数
					if lineNum {
						strSplit[i] = strconv.Itoa(i+1) + ":" + strSplit[i]
					}
				}
				continue
			}

			if strings.Contains(strings.ToLower(v), strings.ToLower(sub_str)) { //如果包含
				//给匹配的行中的关键字加上颜色
				strSplit[i] = strings.ReplaceAll(strSplit[i], sub_str, vars.RedColor(sub_str))
				indexs = append(indexs, i) //记录匹配到的行数
				if lineNum {
					strSplit[i] = strconv.Itoa(i+1) + ":" + strSplit[i]
				}
			}
		} else {
			if isReg {
				re := regexp.MustCompile(sub_str)
				if re.MatchString(v) {
					//给匹配的行中的关键字加上颜色
					strSplit[i] = re.ReplaceAllStringFunc(v, func(s string) string {
						return vars.RedColor(s)
					})
					indexs = append(indexs, i) //记录匹配到的行数
					if lineNum {
						strSplit[i] = strconv.Itoa(i+1) + ":" + strSplit[i]
					}
				}
				continue
			}

			if strings.Contains(v, sub_str) { //如果包含
				//给匹配的行中的关键字加上颜色
				strSplit[i] = strings.ReplaceAll(strSplit[i], sub_str, vars.RedColor(sub_str))
				indexs = append(indexs, i) //记录匹配到的行数
				if lineNum {
					strSplit[i] = strconv.Itoa(i+1) + ":" + strSplit[i]
				}
			}
		}
	}

	//根据选项进行处理
	for _, v := range optionsSplit {
		//判断是否是a开头
		if strings.HasPrefix(v, "a") {
			numStr := v[1:]
			//判断是否是数字
			if !common.IsInt(numStr) {
				panic("a选项错误,必须是数字b1,b2,b3")
			}
			num, _ := strconv.Atoi(numStr)
			if num < 1 {
				panic("a选项错误,必须大于0")
			}

			//给所有的indexs加上前面的行下下标
			for _, index_ := range indexs {
				var index_A = index_ - num
				if lineNum {
					strSplit[index_A] = strconv.Itoa(index_A+1) + ":" + strSplit[index_A]
				}
				common.InsertSliceEnd(&indexs, index_A)
			}
		}
		//判断是否是b开头
		if strings.HasPrefix(v, "b") {
			numStr := v[1:]
			//判断是否是数字
			if !common.IsInt(numStr) {
				panic("b选项错误,必须是数字b1,b2,b3")
			}
			num, _ := strconv.Atoi(numStr)
			if num < 1 {
				panic("b选项错误,必须大于0")
			}
			//给所有的indexs加上后面的行下标
			for _, index_ := range indexs {
				var index_B = index_ + num
				if lineNum {
					strSplit[index_B] = strconv.Itoa(index_B+1) + ":" + strSplit[index_B]
				}
				common.InsertSliceEnd(&indexs, index_B)
			}
		}
		//判断是否是c开头
		if strings.HasPrefix(v, "c") {
			numStr := v[1:]
			//判断是否是数字
			if !common.IsInt(numStr) {
				panic("c选项错误,必须是数字b1,b2,b3")
			}
			num, _ := strconv.Atoi(numStr)
			if num < 1 {
				panic("c选项错误,必须大于0")
			}
			//给所有的indexs加上前面的行下标
			for _, index_ := range indexs {
				var index_A = index_ - num
				if lineNum {
					strSplit[index_A] = strconv.Itoa(index_A+1) + ":" + strSplit[index_A]
				}
				common.InsertSliceEnd(&indexs, index_A)
			}
			//给所有的indexs加上后面的行下标
			for _, index_ := range indexs {
				var index_B = index_ + num
				if lineNum {
					strSplit[index_B] = strconv.Itoa(index_B+1) + ":" + strSplit[index_B]
				}
				common.InsertSliceEnd(&indexs, index_B)
			}
		}
	}

	//排序(从小到大)
	common.SortSlice(&indexs, 0, func(a, b int) int {
		return a - b
	})
	//将indexs去重
	common.RemoveDuplicate(&indexs, 0, func(a, b int) bool {
		return a == b
	})

	//获取到匹配的所有的行
	var result []string
	for _, index_ := range indexs {
		if index_ >= 0 && index_ < len(strSplit) {
			result = append(result, strSplit[index_])
		}
	}
	join_ := strings.Join(result, global.LineBreak)
	return join_
}

// 判断字符串是否存在,支持正则表达式
func contain(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 判断字符串是否存在,支持正则表达式
签名: contain(字符串,查找字符串)
- 查找字符串:支持正则表达式 '/xxx/'  例如: /45|wo/
案例:
1. contain('hello world','world')  结果:  true
2. contain('hello world','/45|wo/')  结果:  true
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("contains函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	sub1 := args[1]
	//判断是否是正则表达式
	var isReg bool
	if strings.HasPrefix(sub1, "/") && strings.HasSuffix(sub1, "/") {
		sub1 = sub1[1 : len(sub1)-1]
		isReg = true
	}
	//判断是否匹配
	var isContains bool
	if isReg {
		re := regexp.MustCompile(sub1)
		isContains = re.MatchString(str)
	} else {
		isContains = strings.Contains(str, sub1)
	}
	return strconv.FormatBool(isContains)
}

// 判断字符串开头是否匹配
func startWith(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 判断字符串开头是否匹配
签名: startWith(字符串,匹配字符串)
案例:
1. startWith('hello world','hello')  结果:  true
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("startWith函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	sub1 := args[1]
	//判断是否匹配
	isStartWith := strings.HasPrefix(str, sub1)
	return strconv.FormatBool(isStartWith)
}

// 判断字符串结尾是否匹配
func endWith(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 判断字符串结尾是否匹配
签名: endWith(字符串,匹配字符串)
案例:
1. endWith('hello world','world')  结果:  true
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("endWith函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	sub1 := args[1]
	//判断是否匹配
	isEndWith := strings.HasSuffix(str, sub1)
	return strconv.FormatBool(isEndWith)
}

// 获取指定行数的字符串
func at(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 获取之前结果 (管道参数的优先级高于函数的第一个参数)
签名: at(lines,num...)  
- lines: 多行字符串 \n结尾就是一行
- num: 读取的行数  默认为1也就是第一行,也可以输入多个行数,返回多行
- 如果小于1则返回第一行,如果大于最大行数则返回最后一行
案例:
1. 'hello world\n你好'|at     结果:  hello world
2. 'hello world\n你好'|at(2)  结果:  你好
3.  at('hello world\n你好',2) 结果:  你好
4.  at('hello world\n你好')   结果:  hello world
`
	}
	//判断参数是否大于1,并且从第一个参数开始都是数字
	if len(args) > 1 {
		for i := 1; i < len(args); i++ {
			if !common.IsInt(args[i]) {
				panic("at函数参数不正确")
			}
		}
	}
	//如果参数全部是数字,那么就将第一个参数作为lines
	var isAllInt = true
	if len(args) > 1 {
		//判断第一个参数不是数字
		if !common.IsInt(args[0]) {
			isAllInt = false
		}
	}

	//如果参数全部是数字,并且管道有值,那么就将管道的值给第一个参数
	if isAllInt && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//如果没有第二个参数,那么默认为1
	if len(args) == 1 {
		args = append(args, "1")
	}
	//判断参数个数
	if len(args) < 2 {
		panic("at函数参数个数不正确")
	}

	//读取
	str := args[0]
	//识别是否是字符串
	var isStr bool
	if global.IsString(str) {
		isStr = true
		//清理字符串
		str = global.RemoveStrSymbol(str)
	}

	//获取行数
	nums := args[1:]

	//获取所有行
	strSplit := strings.Split(str, global.LineBreak)
	var result strings.Builder
	for _, num := range nums {
		n, _ := strconv.Atoi(num)
		//判断是否超出范围
		if n > len(strSplit) {
			n = len(strSplit)
		}
		if n < 1 {
			n = 1
		}
		result.WriteString(strSplit[n-1])
		result.WriteString(global.LineBreak)
	}
	//去掉最后一个换行符
	right := strings.TrimRight(result.String(), global.LineBreak)
	if isStr {
		return global.AddStrSymbol(right)
	}
	return right
}

// 字符串拼接
func concat(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 字符串拼接
签名: concat(字符串1,字符串2)
案例:
1. concat('hello','world')  结果:  helloworld
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 2 {
		panic("concat函数参数个数不正确")
	}
	//拆分参数
	str1 := args[0]
	var isStr1 bool
	if global.IsString(str1) {
		isStr1 = true
		str1 = global.RemoveStrSymbol(str1)
	}

	str2 := args[1]
	//拼接
	str := str1 + str2
	if isStr1 {
		return global.AddStrSymbol(str)
	}
	return str
}

// 去掉字符串两边的空格
func trim(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 去掉字符串两边的空格
签名: trim(字符串)
案例:
1. trim(' hello world ')  结果:  hello world
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 1 {
		panic("trim函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	//去掉两边的空格
	str = strings.TrimSpace(str)
	return str
}

// 字符串转换为大写
func upper(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 字符串转换为大写
签名: upper(字符串)
案例:
1. upper('hello world')  结果:  HELLO WORLD
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 1 {
		panic("upper函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	//转换为大写
	str = strings.ToUpper(str)
	return str
}

// 字符串转换为小写
func lower(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 字符串转换为小写
签名: lower(字符串)
案例:
1. lower('HELLO WORLD')  结果:  hello world
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 1 {
		panic("lower函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	//转换为小写
	str = strings.ToLower(str)
	return str
}

// 驼峰转换,自动识别然后转换为对应的驼峰
func camel(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 驼峰转换
签名: camel(字符串,类型)
- 类型: 1:首字母大写驼峰 2:首字母小写驼峰 3:下划线转驼峰(小写) 4:下划线转驼峰(大写)
案例:
1. camel('hello world',1)  结果:  HelloWorld
2. camel('hello_world',2)  结果:  helloWorld
3. camel('helloWorld',3)  结果:  hello_world
4. camel('helloWorld',4)  结果:  HELLO_WORLD
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 2 {
		panic("camel函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	//判断是否符合转换规则
	if !(strings.Contains(str, " ") || strings.Contains(str, "_") || (common.IsUpper(str) && common.IsLower(str))) {
		panic("字符串不符合转换规则,只支持:\n" +
			"- HelloWorld  , helloWorld\n" +
			"- hello_world , HELLO_WORLD , hello_WORLD ,HELLO_world\n" +
			"- hello world , HELLO WORLD , hello WORLD ,HELLO world\n")
	}

	_type, _ := strconv.Atoi(args[1])
	newType := _type

	var funHand = func(strSplit []string, _type int) string {
		for i, v := range strSplit {
			//如果是空,那么就跳过
			if len(strings.TrimSpace(v)) == 0 {
				continue
			}
			//根据类型进行转换
			switch newType {
			case 1: //大驼峰
				//首字母大写
				title := cases.Title(language.Und, cases.NoLower)
				strSplit[i] = title.String(v)
			case 2:
				//首字母小写
				strSplit[i] = strings.ToLower(v[:1]) + v[1:]
				newType = 1
			case 3:
				//全部小写
				strSplit[i] = strings.ToLower(v) + "_"
			case 4:
				//全部大写
				strSplit[i] = strings.ToUpper(v) + "_"
			}
		}
		//拼接
		str = strings.Join(strSplit, "")
		newType = _type
		//如果类型是3或者4,那么就去掉最后一个下划线
		if newType == 3 || newType == 4 {
			str = str[:len(str)-1]
		}
		return str
	}

	//先拆分字符串
	strSplit := strings.Split(str, "_")
	if len(strSplit) > 1 {
		str = funHand(strSplit, _type)
	}
	//根据空格进行分割
	strSplit = strings.Split(str, " ")
	if len(strSplit) > 1 {
		str = funHand(strSplit, _type)
	}

	//如果类型是4直接返回
	strSplit_pd := strings.Split(str, "_")
	if _type == 4 && len(strSplit_pd) > 1 {
		return str
	}

	//根据大写字母进行分割
	//找到大写字母
	re := regexp.MustCompile("[A-Z]")
	indexs := re.FindAllStringIndex(str, -1)
	//如果没有大写字母,那么就返回
	if len(indexs) < 2 {
		return str

	}
	//然后根据大写字母进行分割
	var result []string
	result = append(result, str[:indexs[0][0]])
	for i := 1; i <= len(indexs); i++ {
		if i == len(indexs) {
			result = append(result, str[indexs[i-1][0]:])
			break
		}
		result = append(result, str[indexs[i-1][0]:indexs[i][0]])
	}
	str = funHand(result, _type)
	return str

}

// 字符串反转
func reverse(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 字符串反转
签名: reverse(字符串)
案例:
1. reverse('hello world')  结果:  dlrow olleh
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 1 {
		panic("reverse函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	//反转
	str = common.Reverse(str)
	return str
}

// 正则表达式提取
func pick(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 正则表达式提取,返回所有匹配的字符串
签名: pick(字符串,正则表达式)
案例:
1. pick('hello world','/hello/')  结果:  hello
2. pick('hello world','/hello|world/')  结果:  hello\nworld
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) != 2 {
		panic("pick函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	regStr := args[1]
	//判断是否是正则表达式
	if !strings.HasPrefix(regStr, "/") || !strings.HasSuffix(regStr, "/") {
		panic("正则表达式必须以/开始和结束")
	}
	regStr = regStr[1 : len(regStr)-1]
	//编译正则表达式
	regexpStrs := common.RegexpStrs(str, regStr)
	//返回结果到管道中
	join_ := strings.Join(regexpStrs, global.LineBreak)
	return join_
}

// 截取一个字符
func charAt(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 截取一个字符
签名: charAt(字符串,位置)
- 位置从0开始
案例:
1. charAt('hello world',1)  结果:  e
2. charAt('hello world')    结果:  h
`
	}

	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) < 2 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) == 1 { //这种情况是charAt('hello world')
		args = append(args, "0")
	}
	//判断参数个数
	if len(args) != 2 {
		panic("charAt函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	index_, _ := strconv.Atoi(args[1])
	//判断位置
	if index_ < 0 || index_ >= len(str) {
		panic("位置不正确")
	}
	//截取
	strSub := str[index_ : index_+1]
	return strSub
}
func eq(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 比较两个字符串是否相等
签名: eq(字符串1,字符串2)
- 返回结果是否相等
案例:
1. eq('hello world','hello world')  结果:  true
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("eq函数参数个数不正确")
	}
	//拆分参数
	str1 := args[0]
	str2 := args[1]
	//比较
	isEq := str1 == str2
	return strconv.FormatBool(isEq)
}

// 忽略大小写比较
func eqIgnore(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 忽略大小写比较  (不区分类型)
签名: eqIgnore(字符串1,字符串2)
- 返回结果是否相等
案例:
1. eqIgnore('hello world','HELLO WORLD')  结果:  true
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("eqIgnore函数参数个数不正确")
	}
	//拆分参数
	str1 := args[0]
	str2 := args[1]
	//比较
	isEq := strings.EqualFold(str1, str2)
	return strconv.FormatBool(isEq)
}

func format(args ...string) string {
	//判断第一个参数是-doc
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: format
签名: format(字符串,参数1,参数2...)
- 参数: 用于替换字符串中的占位符
- 占位符: {0},{1}... 从0开始
案例:
1. format('hello {0}','world')  结果:  hello world
2. format('hello {0} {1}','world','go')  结果:  hello world go
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) < 2 {
		panic("format函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	//替换
	for i := 1; i < len(args); i++ {
		str = strings.Replace(str, "{"+strconv.Itoa(i-1)+"}", args[i], -1)
	}
	return str
}

func and(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 求逻辑与 ,只要有一个为false,那么就返回false
签名: and(value1,value2,...)
- value 可以是整数或者浮点数 ,0表示false,非0表示true
示例:
1. and(1,2,3) 返回值为 true
2. and(-1,2,3) 返回值为 false
3. and(true,true) 返回值为 true
`
	}
	if container.GetPrePipelineData().Data != "" {
		data := container.GetPrePipelineData().Data
		//判断是否有分隔符,如果有分隔符,那么就拆分
		if strings.Contains(data, global.LineBreak) {
			args1 := strings.Split(data, global.LineBreak)
			args = append(args1, args...) //将管道的数据放到函数的第一个参数
		} else {
			container.GetPrePipelineDataAndData(&args)
		}
	}
	if len(args) < 2 {
		panic("and函数参数个数不正确")
	}
	//判断args是否都是数值或者bool
	for _, arg := range args {
		if !common.IsNumber(arg) && !(arg == "true" || arg == "false") {
			panic("and函数参数计算结果必须是数值或布尔:" + arg)
		}
	}
	var res bool
	for i, arg := range args {
		if i == 0 {
			//判断是否是bool
			if arg == "true" {
				res = true
				continue
			}
			if arg == "false" {
				res = false
				continue
			}
			parseFloat, err := strconv.ParseFloat(arg, 64)
			if err != nil {
				panic("and函数参数必须是数值或者布尔:" + arg)
			}
			if parseFloat != 0 {
				res = true
				continue
			} else {
				res = false
				continue
			}

		} else {
			//如果有一个是false,那么后面就不用判断了
			if !res {
				res = false
				break
			}

			//false && false
			if arg == "false" {
				res = false
				break
			}
			if arg == "true" {
				res = true
				continue
			}

			parseFloat, err := strconv.ParseFloat(arg, 64)
			if err != nil {
				panic("and函数参数必须是数值或者布尔:" + arg)
			}
			if parseFloat != 0 {
				res = true
				continue
			} else {
				res = false
				break
			}
		}

	}
	return strconv.FormatBool(res)
}

func or(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 求逻辑或  只要有一个为true,那么就返回true
签名: or(value1,value2,...)
- value 可以是整数或者浮点数 ,0表示false,非0表示true
示例:
1. or(1,2,0) 返回值为 true
2. or(-1,0,3) 返回值为 true
3. or(false,false) 返回值为 false
4. or(false,true) 返回值为 true
`
	}
	if container.GetPrePipelineData().Data != "" {
		data := container.GetPrePipelineData().Data
		//判断是否有分隔符,如果有分隔符,那么就拆分
		if strings.Contains(data, global.LineBreak) {
			args1 := strings.Split(data, global.LineBreak)
			args = append(args1, args...) //将管道的数据放到函数的第一个参数
		} else {
			container.GetPrePipelineDataAndData(&args)
		}
	}
	if len(args) < 2 {
		panic("or函数参数个数不正确")
	}
	//判断args是否都是数值或者bool
	for _, arg := range args {
		if !common.IsNumber(arg) && !(arg == "true" || arg == "false") {
			panic("or函数参数计算结果必须是数值或布尔:" + arg)
		}
	}
	var res bool
	for i, arg := range args {
		if i == 0 {
			//判断是否是bool
			if arg == "true" {
				res = true
				break
			}
			if arg == "false" {
				res = false
				continue
			}
			parseFloat, err := strconv.ParseFloat(arg, 64)
			if err != nil {
				panic("or函数参数必须是数值或者布尔:" + arg)
			}
			if parseFloat != 0 {
				res = true
				break
			} else {
				res = false
				continue
			}
		} else {

			//true || true
			if arg == "true" {
				res = true
				break
			}
			if arg == "false" {
				res = false
				continue
			}
			parseFloat, err := strconv.ParseFloat(arg, 64)
			if err != nil {
				panic("or函数参数必须是数值或者布尔:" + arg)
			}
			if parseFloat != 0 {
				res = true
				break
			} else {
				res = false
				continue
			}
		}
	}
	return strconv.FormatBool(res)
}

// 取反
func not(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 求逻辑非
签名: not(value)
- value 可以是整数或者浮点数 ,0表示false,非0表示true
示例:
1. not(1) 返回值为 false
2. not(0) 返回值为 true
`
	}
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		args = append(args, container.GetPrePipelineData().Data)
	}
	if len(args) != 1 {
		panic("not函数参数个数不正确")
	}

	//拆分参数
	arg := args[0]
	if arg == "true" {
		arg = "false"
		return arg
	}
	if arg == "false" {
		arg = "true"
		return arg
	}
	parseFloat, err := strconv.ParseFloat(arg, 64)
	if err != nil {
		panic("not函数参数必须是数值或者bool:" + arg)
	}
	if parseFloat != 0 {
		arg = "false"
		return arg
	} else {
		arg = "true"
		return arg
	}
}

// 大于
func gt(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 大于
签名: gt(value1,value2)
- value 可以是整数或者浮点数
示例:
1. gt(1,2) 返回值为 false
2. gt(2,1) 返回值为 true
3. gt(1.1,1.2) 返回值为 false
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("gt函数参数个数不正确")
	}
	//拆分参数
	arg1 := args[0]
	arg2 := args[1]
	parseFloat1, err := strconv.ParseFloat(arg1, 64)
	if err != nil {
		panic("gt函数参数必须是数值:" + arg1)
	}
	parseFloat2, err := strconv.ParseFloat(arg2, 64)
	if err != nil {
		panic("gt函数参数必须是数值:" + arg2)
	}
	//比较
	res := parseFloat1 > parseFloat2
	return strconv.FormatBool(res)
}

// 大于等于
func ge(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 大于等于
签名: ge(value1,value2)
- value 可以是整数或者浮点数
示例:
1. ge(1,2) 返回值为 false
2. ge(2,1) 返回值为 true
3. ge(1,1) 返回值为 true
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("ge函数参数个数不正确")
	}
	//拆分参数
	arg1 := args[0]
	arg2 := args[1]
	parseFloat1, err := strconv.ParseFloat(arg1, 64)
	if err != nil {
		panic("ge函数参数必须是数值:" + arg1)
	}
	parseFloat2, err := strconv.ParseFloat(arg2, 64)
	if err != nil {
		panic("ge函数参数必须是数值:" + arg2)
	}
	//比较
	res := parseFloat1 >= parseFloat2
	return strconv.FormatBool(res)

}

func lt(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 小于
签名: lt(value1,value2)
- value 可以是整数或者浮点数
示例:
1. lt(1,2) 返回值为 true
2. lt(2,1) 返回值为 false
3. lt(1.1,1.2) 返回值为 true
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("lt函数参数个数不正确")
	}
	//拆分参数
	arg1 := args[0]
	arg2 := args[1]
	parseFloat1, err := strconv.ParseFloat(arg1, 64)
	if err != nil {
		panic("lt函数参数必须是数值:" + arg1)
	}
	parseFloat2, err := strconv.ParseFloat(arg2, 64)
	if err != nil {
		panic("lt函数参数必须是数值:" + arg2)
	}
	//比较
	res := parseFloat1 < parseFloat2
	return strconv.FormatBool(res)
}

func le(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 小于等于
签名: le(value1,value2)
- value 可以是整数或者浮点数
示例:
1. le(1,2) 返回值为 true
2. le(2,1) 返回值为 false
3. le(1,1) 返回值为 true
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("le函数参数个数不正确")
	}
	//拆分参数
	arg1 := args[0]
	arg2 := args[1]
	parseFloat1, err := strconv.ParseFloat(arg1, 64)
	if err != nil {
		panic("le函数参数必须是数值:" + arg1)
	}
	parseFloat2, err := strconv.ParseFloat(arg2, 64)
	if err != nil {
		panic("le函数参数必须是数值:" + arg2)
	}
	//比较
	res := parseFloat1 <= parseFloat2
	return strconv.FormatBool(res)
}
func ne(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 不等于
签名: ne(value1,value2)
- value 可以是整数或者浮点数
示例:
1. ne(1,2) 返回值为 true
2. ne(2,1) 返回值为 true
3. ne(1,1) 返回值为 false
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("ne函数参数个数不正确")
	}
	//拆分参数
	arg1 := args[0]
	arg2 := args[1]
	parseFloat1, err := strconv.ParseFloat(arg1, 64)
	if err != nil {
		panic("ne函数参数必须是数值:" + arg1)
	}
	parseFloat2, err := strconv.ParseFloat(arg2, 64)
	if err != nil {
		panic("ne函数参数必须是数值:" + arg2)
	}
	//比较
	res := parseFloat1 != parseFloat2
	return strconv.FormatBool(res)
}

// if函数
// if(条件1,结果1,条件2,结果2,条件3,结果3,结果4) //最后一个是默认结果,那么如何判断最后一个是默认结果呢,那么参数长度-2如果是奇数,那么就是存在默认结果
func _if_(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 条件判断
签名: if(条件1,结果1,条件2,结果2,条件3,结果3,默认结果4)
- 条件: 布尔值
示例:
1. true|if|hello+world 返回值为 hello+world 
2. if(true,'hello','world') 返回值为 hello  等同: if   else
3. if(false,'hello','world') 返回值为 world 等同: if   else
4. if(false,'hello',false,'world','xxx')   返回值为 xxx  ,等同: if   elseif 
5. if(false,'hello',true,'world','xxx','ccc')   返回值为 world  ,等同: if   elseif else
注意: 
1. if参数大于或等于1的时候不会主动获取前一个管道的值,如果需要获取前一个管道的值,那么需要手动调用##或者#1,#2,#3...来获取
2. if没有参数的时候会自动获取前一个管道的值,只有为true的时候才会返回结果,否则会停止管道继续执行
3. if没有else,那么不满足条件的时候会停止管道继续执行
`
	}
	//判断参数没有
	if len(args) == 0 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	//判断参数个数
	if len(args) < 1 {
		panic("if函数参数个数不正确,参数个数不能小于1个")
	}
	//判断参数是否只有1个
	if len(args) == 1 {
		tokens := code_analysis.CodeToTokens(args[0])
		var is string
		if manager.IsExpression(tokens) {
			is = expression.CalculateCore(tokens)
		} else {
			is = args[0]
		}
		if common.IsTrue(is) {
			return container.GetPrePipelineData().Data
		} else {
			global.StopPipe = true //停止管道继续执行
			return ""
		}
	}

	//判断是否有默认条件
	var defaultVal bool
	//长度-2如果是奇数,那么就是存在默认结果
	if (len(args)-2)%2 != 0 {
		defaultVal = true
	}
	var len_ = len(args)
	if defaultVal {
		len_ = len_ - 1
	}

	//遍历参数,不会出现函数的,因为在前面已经处理了,只会出现表达式
	for i := 0; i < len_; i += 2 {

		var is string
		tokens := code_analysis.CodeToTokens(args[i])
		if manager.IsExpression(tokens) {
			is = expression.CalculateCore(tokens)
		} else {
			is = args[i]
		}
		if common.IsTrue(is) {
			return manager.CodeRun(args[i+1])
		}
	}
	//如果有默认结果
	if defaultVal {
		return manager.CodeRun(args[len(args)-1])
	} else {
		global.StopPipe = true //停止管道继续执行
	}
	return ""
}

func scan(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 多行内容扫描迭代器
签名: scan(值,内容)
- 值: 多行字符串
- 内容: 函数或者表达式
示例:
1. scan('hello\nworld','upper') 返回值为 HELLO\nWORLD
参数2中每次调用都能获取到遍历的值,和正常的函数一样, 遍历结束后会自动清空恢复之前的管道
`
	}
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if len(args) == 1 && container.GetPrePipelineData().Data != "" {
		container.GetPrePipelineDataAndData(&args)
	}
	if len(args) != 2 {
		panic("scan函数参数个数不正确")
	}
	//拆分参数
	str := args[0]
	content := args[1]
	//判断是否是多行,如果不是多行,那么就直接返回
	if !strings.Contains(str, global.LineBreak) {
		return str
	}
	strSplit := strings.Split(str, global.LineBreak)
	var strBuilder strings.Builder
	//保留管道
	var oldPipelineDataSlice = make([]container.PipelineData, len(container.PipelineDataSlice))
	var indexPipe = global.IndexPipe
	copy(oldPipelineDataSlice, container.PipelineDataSlice)
	for _, v := range strSplit {
		//将i放入到管道中
		data := container.NewPipelineData(v)
		container.RegisterPipelineData(data)
		codeRun := manager.CodeRun(content)
		strBuilder.WriteString(codeRun)
		strBuilder.WriteString(global.LineBreak)
	}
	//切换回原来的管道
	container.PipelineDataSlice = oldPipelineDataSlice
	global.IndexPipe = indexPipe
	//去掉最后一个换行符
	str_ := strBuilder.String()
	str_ = str_[:len(str_)-len(global.LineBreak)]
	return str_
}

func _system_(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 执行系统命令
签名: system(命令)
- 命令: 系统命令
示例:
1. system('ls') 返回值为 xxx
2. '123\n333\n4444'| system('findstr 33')  返回值为 333
`
	}
	if len(args) != 1 {
		panic("system函数参数个数不正确")
	}
	//拆分参数
	cmdStr := args[0]
	//如果管道有值,那么就将前一个管道的值给函数第一个
	if container.GetPrePipelineData().Data != "" {
		data := container.GetPrePipelineData().Data
		//去掉字符串
		data = global.RemoveStrSymbol(data)
		//将自定义换行符替换为系统换行符
		data = strings.Replace(data, global.LineBreak, vars.SystemLineBreak, -1)
		//写入到标准输入
		run := cmd.PipeRun(data, cmdStr)
		//分割
		breakReplace := manager.LineBreakReplace(run)
		return breakReplace
	}

	run := cmd.Run(cmdStr)
	//分割
	breakReplace := manager.LineBreakReplace(run)
	return breakReplace
}

func sync(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 将管道执行的结果同步到原始数据中 (限制有点多,好好阅读文档使用)
签名: sync()
示例:
1. '你好\nxxx3322xxx\n你好\nxx12313xx'|grep('/\d+/')|pick('/\d+/')|scan(sub(1,3))|scan(sum(1))|sync 
    返回值为你好\nxxx3332xxx\n你好\nxx12413xx
说明: 
1.sync同步函数必须在管道的最后一个使用
2.管道数据流必须大于等于3个,因为只是2个数据流,那么就没有同步的意义。因为单个函数就能完成 
  比如 '你好\nxxx33|sync' 或者 '你好\nxxx33'|grep('/\d+/')|sync  都是没有意义的
3.管道处理数据一般最少3因为一般第一个数据流是原始数据,第二个数据流是搜索,第三个数据流才是处理
4.你可以这样理解想使用sync,基本必须有grep函数找出需要处理的行,然后根据情况是否使用pick函数找到需要处理的数据块,然后进行处理
5.正确流程: 原始数据数据|grep(正则)|pick(正则)|scan(处理函数)|sync(同步数据到原始数据)
6.注意: 一旦使用不当得到的结果就是不可预知的
`
	}
	//判断参数个数
	if len(args) != 0 {
		panic("sync函数参数个数不正确")
	}
	slice := container.PipelineDataSlice
	//判断管道是否有值
	if len(slice) == 0 || len(slice[0].Data) == 0 {
		panic("管道没有值,不能同步")
	}
	//管道长度必须大于或等于slice[2]
	if len(slice) < 3 {
		panic("管道长度必须大于或等于3,否则不能同步")
	}
	var hitData []*string
	//获取管道1的值
	data1 := slice[0].Data
	data1 = global.RemoveStrSymbol(data1)
	data1s := strings.Split(data1, global.LineBreak)
	//获取管道2的值
	data2 := slice[1].Data
	data2s := strings.Split(data2, global.LineBreak)

	//找到管道2存在管道1中的数据,将引用放入到hitData中
	for i, _ := range data2s {
		for i1, v := range data1s {
			if v == data2s[i] {
				hitData = append(hitData, &data1s[i1])
			}
		}

	}

	for row, _ := range hitData {
		data1__ := *hitData[row]
		var startIndex = 0
		var endIndex = len(data1__)
		var swap = data1__
		var rows = len(slice) //总行数
		for i := 2; i < rows; i++ {
			datas := strings.Split(slice[i].Data, global.LineBreak)
			//判断datas长度是否满足row
			if len(datas)-1 < row {
				continue
			}
			data := datas[row]
			//判断data是swap的子集
			if strings.Contains(swap, data) {
				//找到位置
				newStartIndex := strings.Index(swap, data)
				startIndex += newStartIndex
				endIndex = startIndex + len(data)
				swap = data
			} else {
				swap = data
				//如果不是子集那么就替换原始数据
				var per = data1__[:startIndex]
				var next = data1__[endIndex:]
				data1__ = per + data + next
				//更新结束位置
				endIndex = startIndex + len(data)
			}
		}
		*hitData[row] = data1__
	}
	newData := strings.Join(data1s, global.LineBreak)
	return newData

}

func reset(args ...string) string {
	if len(args) > 0 && args[0] == "-doc" {
		return `
功能: 重置管道数据,将最后一个数据作为原始数据重新开始一个新的管道
      一般需要配合sync函数使用
签名: reset()
说明:
 比如一个文本有1万行数据,进过筛选我只要100条数据
 处理后使用sync会将100条数据同步到原始数据中并打印之前的1万行数据
 这就不符合我们想要的了, 我们只想要这100条数据,那么就需要reset函数,
 将这100条数据作为原始数据,然后再进行处理,之后在使用sync,这样打印的就是这100条数据
`
	}
	// 判断参数个数
	if len(args) != 0 {
		panic("reset函数参数个数不正确")
	}
	//获取最后一个数据
	data := container.GetPrePipelineData()
	//清空管道
	container.ClearPipelineData()
	return data.Data
}
